package com.bid.base.common.util;

import java.nio.charset.StandardCharsets;

import java.security.Key;

import java.security.KeyFactory;

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.Signature;

import java.security.interfaces.RSAPrivateKey;

import java.security.interfaces.RSAPublicKey;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.HashMap;

import java.util.Map;

import javax.crypto.Cipher;

//import com.bid.wechat.encrypt.sm4.AESUtil;
import com.bid.base.common.util.sm4.AESUtil;
import sun.misc.BASE64Decoder;

import sun.misc.BASE64Encoder;

/**
 * RSA非对称算法
 *
 * @author chenxy
 */

public final class RSAUtil {
    /**
     * 私钥解密
     *
     * @param data       需解密的数据
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */

    public static byte[] decryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        Key key = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, key);

        return cipher.doFinal(data);

    }

    /**
     * 公钥解密
     *
     * @param data      需解密的数据
     * @param publicKey 公钥
     * @return
     * @throws Exception
     */

    public static byte[] decryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);

        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        Key key = keyFactory.generatePublic(x509EncodedKeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, key);

        return cipher.doFinal(data);

    }

    /**
     * 私钥加密
     *
     * @param data       需加密的数据
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */

    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        Key key = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, key);

        return cipher.doFinal(data);

    }

    /**
     * 公钥加密
     *
     * @param data      需加密的数据
     * @param publicKey 公钥
     * @return
     * @throws Exception
     */

    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);

        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        Key key = keyFactory.generatePublic(x509EncodedKeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, key);

        return cipher.doFinal(data);

    }

    /**
     * 获取私钥
     *
     * @param keyMap 密钥Map
     * @return
     * @throws Exception
     */

    public static String getPrivateKey(Map keyMap) throws Exception {
        Key key = (Key) keyMap.get("PrivateKey");

        return new BASE64Encoder().encode(key.getEncoded());

    }

    /**
     * 获取公钥
     *
     * @param keyMap 密钥Map
     * @return
     * @throws Exception
     */

    public static String getPublicKey(Map keyMap) throws Exception {
        Key key = (Key) keyMap.get("PublicKey");

        return new BASE64Encoder().encode(key.getEncoded());

    }

    /**
     * 初始化密钥
     *
     * @return
     * @throws Exception
     */

    public static Map initKey() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

        keyPairGenerator.initialize(1024);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        Map keyMap = new HashMap(2);

        keyMap.put("PublicKey", publicKey);

        keyMap.put("PrivateKey", privateKey);

        return keyMap;

    }

    public static void main(String[] args) {
        try {
            Map map = initKey();
            String gy = getPublicKey(map);
            String sy = getPrivateKey(map);
            System.out.println("公钥：\t" + gy);
            System.out.println("私钥：\t" + sy);

            String context = "fasdfsdfsdf";
            byte[] enContext = encryptByPrivateKey(context.getBytes(StandardCharsets.UTF_8), sy);

            String byte2HexStr = AESUtil.parseByte2HexStr(enContext);
            System.out.println(" 加密之后的str: \t " + byte2HexStr);

            byte[] deContext = decryptByPublicKey(AESUtil.parseHexStr2Byte(byte2HexStr), gy);
            System.out.println("2解密之后：" +new String(deContext));

        } catch (Exception e) {
// TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

    /**
     * 私钥签名
     *
     * @param data       需签名的数据
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */

    public static String signByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey key = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5withRSA");

        signature.initSign(key);

        signature.update(data);

        return new BASE64Encoder().encode(signature.sign());

    }

    /**
     * 公钥校验
     *
     * @param data      需校验的数据
     * @param publicKey 公钥
     * @param sign      签名
     * @return
     * @throws Exception
     */

    public static boolean verifyByPublicKey(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);

        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PublicKey key = keyFactory.generatePublic(x509EncodedKeySpec);

        Signature signature = Signature.getInstance("MD5withRSA");

        signature.initVerify(key);

        signature.update(data);

        return signature.verify(new BASE64Decoder().decodeBuffer(sign));

    }

    private RSAUtil() {
    }

}
